<?php

namespace App\HttpController;

use EasySwoole\Http\AbstractInterface\Controller;
use EasySwoole\EasySwoole\ServerManager;
use App\Common\PlayCommon;
use App\Utility\BaseEnum;
use App\Common\AuthCommon;
use App\Utility\RedisTools;

/**
 * Class WebSocket
 *
 * 此类是通过 http 请求来调用具体的事件
 * 实际生产中需要自行管理 fd -> user 的关系映射，这里不做详细解释
 *
 * @package App\HttpController
 */
class WebSocket extends Controller
{
    protected $request_client_fd  = FALSE;
    public function index(){
        $this->response()->write("SERVIER-ERROR");
    }
    
    /**
     * TODO使用HTTP触发广播给所有的WS客户端
     *
     * @example http://ip:9501/WebSocketTest/broadcast
     */
    public function broadcast()
    {
        /** @var \swoole_websocket_server $server */
        $server = ServerManager::getInstance()->getSwooleServer();
        $start = 0;

        // 此处直接遍历所有FD进行消息投递
        // 生产环境请自行使用Redis记录当前在线的WebSocket客户端FD
        while (true) {
            $conn_list = $server->connection_list($start, 10);
            if (empty($conn_list)) {
                break;
            }
            $start = end($conn_list);
            foreach ($conn_list as $fd) {
                $info = $server->getClientInfo($fd);
                /** 判断此fd 是否是一个有效的 websocket 连接 */
                if ($info && $info['websocket_status'] == WEBSOCKET_STATUS_FRAME) {
                    $server->push($fd, 'http broadcast fd ' . $fd . ' at ' . date('H:i:s'));
                }
            }
        }
    }
    
    protected function ResMSG($code = -1, $msg = ""){
        $sendRes = ["code"=> $code, "msg"=> $msg];
        $this->response()->write(json_encode($sendRes));
    }
    

  /**
    * TODO  HTTP触发向某个客户端单独推送消息
    * @example http://ip:9501/WebSocketTest/push?fd=2
    */
    public function push()
    {
        $fdStr = $this->request()->getRequestParam('fd');
        $pushtype = $this->request()->getRequestParam('ptype');
        $fdList = !empty($fdStr) ? explode(',', $fdStr) : FALSE ;
        $sendMsg = $this->request()->getRequestParam('pushdata'); //发送的消息内容
        
        //获取内容
        if(empty($fdList) || !$fdList){
            $this->ResMSG(0,"客户端异常");
            return FALSE;
        }
        
        //组装数据格式
        $sendMsg = PlayCommon::getPushContextByType($pushtype , $sendMsg , $fdList);  //格式
        if(!$sendMsg || empty($sendMsg)){
            $this->ResMSG(0,"暂无消息需要推送");
            return FALSE;
        }
        
        $server = ServerManager::getInstance()->getSwooleServer();
        foreach ($fdList as $fdval){
            if (isset($fdval) && intval($fdval) >0) {
                $info = $server->getClientInfo($fdval);
                $fdStatus = $info['websocket_status'] ?? -1;
                if (!empty($info) && $fdStatus != -1 && $fdStatus == WEBSOCKET_STATUS_FRAME) {
                    $server->push($fdval, $sendMsg);
                }
            }
        }
        $this->ResMSG(1,"成功");
    }


    
    /**
     * TODO 通知所有连接客户端
     */
    public function pushLists() {
        $maxUpdateNum =  3; //每次推送客户端数目
        $lastPushMsg = [];
        $gameId = $this->request()->getRequestParam('gameId');
        $pushtype = $this->request()->getRequestParam('ptype');
        $pushdata = $this->request()->getRequestParam('pushdata'); //推送数据内容
        $pushdata = !empty($pushdata) ? json_decode($pushdata,TRUE) : FALSE;
        $this->request_client_fd  = $this->request()->getSwooleRequest()->fd ;  //当前连接FD的值
        BaseEnum::Logger("HTTP推送全局[pushLists]开始执行：gameId={$gameId}-{$pushtype},http_server_fd =".$this->request_client_fd,"user-login");
        if (!empty($pushdata)) {
            foreach ($pushdata as $onemsg){ //消息处理
                $unitkey = $onemsg['unitkey'] ?? 0;
                $ungameid= $onemsg['gameId'] ?? 0;
                
                //优化KEY值
                if (isset($onemsg["content"]) && !empty($onemsg["content"]) && intval($unitkey) > 0) {
                    $lastPushMsg[] = ["gameId"=>$ungameid,"timestamp"=> $unitkey,"content"=> $onemsg["content"]] ;
                }
            }
        }
        if (!$lastPushMsg) { return FALSE;}
        
        
        //TODO 所有连接列表值
        $clientsRes = FALSE;
        $first_fd = 0;
        //TODO 获取连接列表
        $clientsRes = ServerManager::getInstance()->getSwooleServer() -> getClientList($first_fd,$maxUpdateNum);
        while (!empty($clientsRes) && sizeof($clientsRes) > 0) {
            
            $first_fd = end($clientsRes); //最后一个FD
            BaseEnum::Logger("TO线程[pushLists] 执行推送：FirstFd={$first_fd},getClients =".json_encode($clientsRes),"user-login");
            foreach($clientsRes as $oneFd){
                if ($oneFd != $this->request_client_fd) {
                    $pushdata = ['m'=> BaseEnum::XYM_0XAO,"data"=> $lastPushMsg ];
                    AuthCommon::pushFrontWeb($oneFd,json_encode($pushdata));
                    BaseEnum::Logger("记录[pushONE] 推送：FD={$oneFd},MSG =".json_encode($pushdata)  ,"user-login");
                }
            }
            
            //更新是否还有下一轮人员
            $clientsRes = ServerManager::getInstance()->getSwooleServer() -> getClientList($first_fd,$maxUpdateNum);
            BaseEnum::Logger("NEXT 线程[pushLists] 执行推送：FirstFd={$first_fd},getClients =".json_encode($clientsRes),"user-login");
            if(!$clientsRes){
                break;
            }
        }
        $this->response()->write("DO--PUSH FINISH");
    }

}
